/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.webapp.util.core;

import org.apache.commons.digester.Digester;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;

import javax.servlet.ServletContext;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>Parser for deployment descriptor of our web application.</p>
 * <p><a href="DescriptorParser.java.html"><i>View Source</i></a></p>
 *
 * @author Sergey Zubtsovskiy <a href="mailto:sergey.zubtsovskiy@blandware.com">&lt;sergey.zubtsovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.4 $ $Date: 2006/08/03 10:08:26 $
 */
public class DescriptorParser {

	protected transient final Log log = LogFactory.getLog(getClass());

	/**
	 * Public ID of webapp 2.3 DTD
	 */
	private static final String WEB_APP_2_3_DTD_PUBLIC_ID = "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN";

	/**
	 * Location of webapp 2.3 DTD
	 */
	private static final String WEB_APP_2_3_DTD_LOCATION = "/org/apache/struts/resources/web-app_2_3.dtd";

	/**
	 * Default path to deployment descriptor
	 */
	protected String configPath = "/WEB-INF/web.xml";

	/**
	 * Servlet context of our web application
	 */
	protected ServletContext servletContext;

	/**
	 * Set of security roles
	 */
	protected Map securityRoles = null;

	/**
	 * Creates new instance of DescriptorParser
	 *
	 * @param servletContext Servlet context of our web application
	 */
	public DescriptorParser(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	/**
	 * Returns set of security roles presented in web application deployment descriptor
	 *
	 * @return Set of security roles
	 */
	public Map getSecurityRoles() {

		Digester digester = new Digester();
		digester.push(this);
		digester.setNamespaceAware(true);
		digester.setValidating(false);
		digester.setUseContextClassLoader(true);

		// register DTD
		URL dtdUrl = getClass().getResource(WEB_APP_2_3_DTD_LOCATION);
		digester.register(WEB_APP_2_3_DTD_PUBLIC_ID, dtdUrl.toString());

		digester.addCallMethod("web-app/security-role", "addSecurityRole", 2, new Class[]{String.class, String.class});
		digester.addCallParam("web-app/security-role/role-name", 0);
		digester.addCallParam("web-app/security-role/description", 1);

		InputStream input = servletContext.getResourceAsStream(configPath);

		if ( input == null ) {
			if ( log.isErrorEnabled() ) {
				log.error("Failed to retrieve deployment descriptor by path: " + configPath);
			}
			return null;
		}

		try {
			digester.parse(input);
		} catch ( IOException e ) {
			if ( log.isErrorEnabled() ) {
				StringWriter sw = new StringWriter();
				e.printStackTrace(new PrintWriter(sw));
				log.error(sw.toString());
			}

		} catch ( SAXException e ) {
			if ( log.isErrorEnabled() ) {
				StringWriter sw = new StringWriter();
				e.printStackTrace(new PrintWriter(sw));
				log.error(sw.toString());
			}
		} finally {
			try {
				input.close();
			} catch ( IOException e ) {
				if ( log.isErrorEnabled() ) {
					StringWriter sw = new StringWriter();
					e.printStackTrace(new PrintWriter(sw));
					log.error(sw.toString());
				}
			}
		}

		return securityRoles;
	}

	/**
	 * Adds security role to the set
	 *
	 * @param roleName    Name of role to add
	 * @param description Role description
	 */
	public void addSecurityRole(String roleName, String description) {
		if ( securityRoles == null ) {
			securityRoles = new HashMap();
		}
		securityRoles.put(roleName, description);
	}

	/**
	 * Sets config path
	 *
	 * @param configPath Config path to use
	 */
	public void setConfigPath(String configPath) {
		this.configPath = configPath;
	}

}
